home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995 August: Tool Chest / Dev.CD Aug 95 TC / Dev.CD Aug 95 TC.toast / New System Software Extensions / QuickDraw™ GX 1.1.2 / Programming Stuff / Sample Code / Printing Samples / Printer Drivers… / CustomWriter GX 1.0.3 ƒ / CustomBufferingAndIO.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-20  |  27.8 KB  |  1,039 lines  |  [TEXT/MPS ]

  1. /*
  2.     FILENAME
  3.         CustomBufferingAndIO.c
  4.  
  5.     DESCRIPTION
  6.         Contains code that shows how to implement custom buffering and
  7.         non-standard communications code in a QuickDraw GX printer
  8.         driver.  In this code, we write everything to disk (through our
  9.         own buffers) as an extended version 2 PICT file.
  10.  
  11.     COPYRIGHT
  12.         Copyright © 1995 Apple Computer, Inc.
  13.         All rights reserved.
  14.     
  15.     Modification history
  16.         06/14/95 - Dave Hersey -    Version 1.0.3 to fix a bug in
  17.                                     WriteEndOfPICTFile when creating
  18.                                     high-res PICTs, and to make the size
  19.                                     of buffers more flexible.
  20.  
  21.         05/26/95 - Dave Hersey -    Version 1.0.2 to add the new 'outp'
  22.                                     desktop printer resource in NewApp.c.
  23.  
  24.         05/03/95 - Dave Hersey -    Version 1.0.1 fixes the following bugs
  25.                                     in this file.
  26.                                     
  27.                                     * endPict opcodes not always word aligned
  28.                                     * current buffer not being reset on flush
  29.                                     * gxWriteData override could not handle a
  30.                                       simple flush by passing a nil data or
  31.                                       length parameter.
  32.                                     * gxFinishSendPage, gxCloseConnection, and
  33.                                       gxCleanupOpenConnection overrides were
  34.                                       doing work before forwarding their
  35.                                       messages which should have been done after
  36.                                       the forwards. 
  37.  
  38.         01/14/95 - Dave Hersey -    Spawned.
  39.  
  40.     NOTE: Relevant goodies are listed in MPW's "Mark" menu.
  41.  
  42. */
  43.  
  44. #include "CommonDefines.h"
  45.  
  46.  
  47. /*    -----------------------------------------------------------------------
  48.  
  49.     SD_OpenConnection is an override for gxOpenConnection.  In this routine
  50.     we allocate our custom buffer structures and forward the message to the
  51.     default gxOpenConnection handler.  Since we specify customIO in our
  52.     'iobm' resource, no connection is actually opened.
  53.  
  54.     -----------------------------------------------------------------------    */
  55.  
  56. OSErr SD_OpenConnection()
  57. {
  58.     OSErr    anErr;
  59.     
  60.     // Create our buffers, then forward the message.
  61.  
  62.     anErr = CreateBuffers();
  63.     
  64.     if (!anErr)
  65.         anErr = Forward_GXOpenConnection();
  66.     else
  67.         GXCleanupOpenConnection();
  68.  
  69.     return anErr;
  70. }
  71.  
  72.  
  73. /*    -----------------------------------------------------------------------
  74.  
  75.     SD_CloseConnection is an override for gxCloseConnection.  In this
  76.     routine we forward the message to the default gxCloseConnection
  77.     handler and dispose of our custom buffer structures.
  78.  
  79.     -----------------------------------------------------------------------    */
  80.  
  81. OSErr SD_CloseConnection()
  82. {
  83.     OSErr    anErr;
  84.     
  85.     // Forward the message and dispose of our buffers.
  86.  
  87.     anErr = Forward_GXCloseConnection();
  88.     DisposeBuffers();
  89.  
  90.     return anErr;
  91. }
  92.  
  93.  
  94. /*    -----------------------------------------------------------------------
  95.  
  96.     SD_CleanupOpenConnection is an override for gxCleanupOpenConnection.
  97.     In this routine we forward the message and dispose of our data
  98.     structures that might have been allocated before we got an error in
  99.     our gxOpenConnection code.
  100.  
  101.     -----------------------------------------------------------------------    */
  102.  
  103. void SD_CleanupOpenConnection()
  104. {
  105.     // Forward the message and dispose of our buffers (if any).
  106.  
  107.     Forward_GXCleanupOpenConnection();
  108.     DisposeBuffers();
  109. }
  110.  
  111.  
  112. /*    -----------------------------------------------------------------------
  113.  
  114.     SD_BufferData is an override for the gxBufferData message.  To support
  115.     our custom buffering code, we perform a total override of this message,
  116.     fill up the next available buffer with the data.  We'll store data and,
  117.     if necessary, flush buffers until all of the passed data has been
  118.     processed.
  119.  
  120.     -----------------------------------------------------------------------    */
  121.  
  122. OSErr SD_BufferData(Ptr data, long length, long bufferOptions)  // only override for custom buffering
  123. {
  124.     OSErr                        anErr = noErr;
  125.     register char                *pData = (char *) data;
  126.     register BufferEntryPtr        buffPtr;
  127.     short                        idx, curBuff;
  128.     Boolean                        foundAFreeBuffer;
  129.     long                        dataLeftToStore = length;
  130.     register BufferGroupHdl        buffGrpHdl = (BufferGroupHdl) GetMessageHandlerInstanceContext();
  131.     char    hdlState;
  132.  
  133. #pragma unused(bufferOptions);
  134.  
  135.     // Lock the buffer group.
  136.  
  137.     hdlState = HGetState((Handle) buffGrpHdl);
  138.     HLockHi((Handle) buffGrpHdl);
  139.     
  140.     
  141.     // While there's no error, and more data to store, process data.
  142.  
  143.     while (!anErr && (dataLeftToStore > 0))
  144.     {
  145.         // Fill the current buffer with data and indicate that the buffer is dirty.
  146.  
  147.         curBuff = (*buffGrpHdl)->curBuff;
  148.         buffPtr = &(*buffGrpHdl)->buff[curBuff];
  149.  
  150.         while ((dataLeftToStore > 0) && (buffPtr->curOffset < (*buffGrpHdl)->bufferSize))
  151.         {            
  152.             // Move the data to our buffer.
  153.  
  154.             (*buffPtr->printBuffer)->data[buffPtr->curOffset] = *pData;
  155.             ++(buffPtr->curOffset);
  156.             ++pData;
  157.             --dataLeftToStore;
  158.         }
  159.  
  160.         buffPtr->bufferIsDirty = true;
  161.  
  162.  
  163.         // If dataLeftToStore > 0, it means that we've filled the current buffer,
  164.         // and we need another.  Find a free one.
  165.  
  166.         if (dataLeftToStore > 0)
  167.         {
  168.             foundAFreeBuffer = false;
  169.  
  170.             // If we can find another buffer that's not dirty, we've found
  171.             // a buffer we can store data in.  By specifying numBuffers -1
  172.             // below, we avoid checking the current buffer, which we know
  173.             // is  dirty.
  174.         
  175.             for (idx = 0; idx < ((*buffGrpHdl)->numBuffers -1); idx++)
  176.             {
  177.                 // Search up from the last buffer we checked,
  178.                 // wrapping around if necessary.
  179.  
  180.                 ++curBuff;
  181.                 if (curBuff >= (*buffGrpHdl)->numBuffers)
  182.                     curBuff = 0;
  183.                 
  184.                 buffPtr = &(*buffGrpHdl)->buff[curBuff];
  185.  
  186.                 if (!buffPtr->bufferIsDirty)
  187.                 {
  188.                     foundAFreeBuffer = true;
  189.                     break;
  190.                 }
  191.             }
  192.             
  193.             // If there are no free buffers, flush them all and use
  194.             // buffer 0.
  195.  
  196.             if (!foundAFreeBuffer)
  197.             {
  198.                 anErr = FlushBuffers(buffGrpHdl);
  199.                 curBuff = 0;
  200.             }
  201.             
  202.             // Whatever our current buffer is, store it in our buffer
  203.             // structure.
  204.  
  205.             (*buffGrpHdl)->curBuff = curBuff;
  206.         }
  207.     }
  208.  
  209.     // Restore the state of the buffer group handle.
  210.  
  211.     HSetState((Handle) buffGrpHdl, hdlState);
  212.     return anErr;
  213. }
  214.  
  215.  
  216. /*    -----------------------------------------------------------------------
  217.  
  218.     SD_FreeBuffer is an override for the gxFreeBuffer message.  You only
  219.     need to override this message if you're doing asynchronous I/O.  Since
  220.     we're not, this is only here as a reminder for you.  It does nothing
  221.     but forward the message to the default implementation of gxFreeBuffer.
  222.  
  223.     -----------------------------------------------------------------------    */
  224.  
  225. OSErr SD_FreeBuffer(gxPrintingBuffer *theBuffer)
  226. {
  227.     return Forward_GXFreeBuffer(theBuffer);
  228. }
  229.  
  230.  
  231. /*    -----------------------------------------------------------------------
  232.  
  233.     WriteFileData is a routine that writes the passed data to a file whose
  234.     reference ID is stored in our global data.
  235.  
  236.     -----------------------------------------------------------------------    */
  237.  
  238. OSErr WriteFileData(void *dataBuffer, long dataLength)
  239. {
  240.     long                amtToWrite = dataLength;
  241.     DriverGlobalsHdl    drvrGlobalsHdl = GetDriverGlobals();
  242.  
  243.     // Write some data to our file.
  244.  
  245.     return FSWrite((*drvrGlobalsHdl)->curFileRefNum, &amtToWrite, dataBuffer); 
  246. }
  247.  
  248.  
  249. /*    -----------------------------------------------------------------------
  250.  
  251.     SD_WriteData is an override for gxWriteData.  Here, we flush our custom
  252.     buffers and then write the passed data, if any, to the output file
  253.     using our custom I/O routine, WriteFileData.
  254.  
  255.     -----------------------------------------------------------------------    */
  256.  
  257. OSErr SD_WriteData(Ptr data, long length)
  258. {
  259.     OSErr                        anErr;
  260.     register BufferGroupHdl        buffGrpHdl = (BufferGroupHdl) GetMessageHandlerInstanceContext();
  261.  
  262.     // Flush the buffers, then do the actual write.
  263.  
  264.     anErr = FlushBuffers(buffGrpHdl);
  265.  
  266.     if (!anErr && (data != nil) && (length > 0))
  267.         anErr = WriteFileData(data, length);
  268.  
  269.     return anErr;
  270. }
  271.  
  272.  
  273. /*    -----------------------------------------------------------------------
  274.  
  275.     SD_DumpBuffer is an override for gxDumpBuffer.  Here, we write the
  276.     passed data to the output file using our custom I/O routine,
  277.     WriteFileData.
  278.  
  279.     -----------------------------------------------------------------------    */
  280.  
  281. OSErr SD_DumpBuffer(gxPrintingBuffer *theBuffer)
  282. {
  283.     if (theBuffer->size != 0)
  284.         return WriteFileData(theBuffer->data, theBuffer->size);
  285.     else
  286.         return noErr;
  287. }
  288.  
  289.  
  290. /*    -----------------------------------------------------------------------
  291.  
  292.     SD_ImageJob is an override for gxImageJob.  Here, we create and
  293.     initialize global data that we'll use during imaging.
  294.  
  295.     -----------------------------------------------------------------------    */
  296.  
  297. OSErr SD_ImageJob(gxSpoolFile theSpoolFile, long *closeOptions)
  298. {
  299.     OSErr                anErr;
  300.     FSSpec                anFSSpec;
  301.     short                vRefNum;
  302.     long                dirID, itemSize;
  303.     gxJobInfo            jobInfo;
  304.     Str255                fileName;
  305.     DriverGlobalsHdl    drvrGlobalsHdl;
  306.     
  307.     // Create and store a handle for our global data.
  308.  
  309.     anErr = CreateAndStoreGlobals(&drvrGlobalsHdl);
  310.  
  311.  
  312.     // Now, do some more initialization for the first file we'll write to.
  313.  
  314.     if (!anErr)
  315.     {
  316.         // Determine the name of this document, and append ", Page " to it.
  317.         // We'll use this when we create PICT files.  Again, the string
  318.         // should really come from a resource file, for localization
  319.         // reasons.
  320.  
  321.         itemSize = sizeof(gxJobInfo);
  322.         anErr = GetCollectionItem(GXGetJobCollection(GXGetJob()),
  323.                                   gxJobTag, gxPrintingTagID,
  324.                                   &itemSize, &jobInfo);
  325.  
  326.         nrequire(anErr, GetCollectionItemFailed);
  327.  
  328.         if (jobInfo.documentName[0] > 22)    // If necessary, crop file name so we
  329.             jobInfo.documentName[0] = 22;    // have room for our page # stuff.
  330.             
  331.         BlockMove(&jobInfo.documentName[1], &fileName[1], (long) jobInfo.documentName[0]);
  332.         BlockMove(", Page ", &fileName[jobInfo.documentName[0] +1], 7);
  333.  
  334.         // Now make an FSSpec for this file.
  335.  
  336.         FindFolder(kOnSystemDisk, kDesktopFolderType, kCreateFolder, &vRefNum, &dirID);
  337.         fileName[0] = jobInfo.documentName[0] +7;
  338.         FSMakeFSSpec(vRefNum, dirID, fileName, &anFSSpec);
  339.         BlockMove(&anFSSpec, &(*drvrGlobalsHdl)->fileLocation, sizeof(FSSpec));
  340.  
  341.         // Set the number of pages we've imaged to 0.
  342.  
  343.         (*drvrGlobalsHdl)->pagesImaged = 0;
  344.  
  345.         // With our global data initialized, it's time to forward the
  346.         // gxImageJob message so that the job is processed.
  347.  
  348.         anErr = Forward_GXImageJob(theSpoolFile, closeOptions);
  349.  
  350.         // All done imaging!  Close the last file, if it's still open,
  351.         // and flush the volume so that we get the changes out to disk
  352.         // faster.
  353.  
  354.         if ((*drvrGlobalsHdl)->curFileRefNum)
  355.             FSClose((*drvrGlobalsHdl)->curFileRefNum);
  356.     
  357.         FlushVol("\p", (*drvrGlobalsHdl)->fileLocation.vRefNum);
  358.         
  359. GetCollectionItemFailed:
  360.  
  361.         // However we get here, dispose of the global data we allocated above.
  362.  
  363.         DisposeGlobals();
  364.     }
  365.  
  366.     return anErr;
  367. }
  368.  
  369.  
  370. /*    -----------------------------------------------------------------------
  371.  
  372.     SD_StartSendPage is an override for gxStartSendPage.  Here, we close
  373.     the current file (if any) and open a new one for the next page.  This
  374.     way, we're able to create a PICT file for each page of a document.
  375.  
  376.     -----------------------------------------------------------------------    */
  377.  
  378. OSErr SD_StartSendPage(gxFormat pageFormat)
  379. {
  380.     OSErr                anErr;
  381.     char                numStr[11], maxChars, nextChar;
  382.     long                numLen;
  383.     DriverGlobalsHdl    drvrGlobalsHdl = GetDriverGlobals();
  384.  
  385.     // Close current file, if any.
  386.  
  387.     HLockHi((Handle) drvrGlobalsHdl);
  388.  
  389.     if ((*drvrGlobalsHdl)->curFileRefNum)
  390.     {
  391.         FSClose((*drvrGlobalsHdl)->curFileRefNum); 
  392.         (*drvrGlobalsHdl)->curFileRefNum = (short) nil;
  393.     }
  394.     
  395.     // Bump the number of pages imaged, and use that in the
  396.     // filename for the next page.  We started pagesImaged at
  397.     // 0, so the first filename will have a 1 appended to it.
  398.  
  399.     (*drvrGlobalsHdl)->lastYPos = 0;
  400.     ++(*drvrGlobalsHdl)->pagesImaged;
  401.  
  402.     NumToString((*drvrGlobalsHdl)->pagesImaged, (void *) numStr);
  403.     numLen = (unsigned long) numStr[0];
  404.     maxChars = 31 -numLen; 
  405.  
  406.     if ((*drvrGlobalsHdl)->fileLocation.name[0] > maxChars)
  407.         (*drvrGlobalsHdl)->fileLocation.name[0] = maxChars;
  408.  
  409.     nextChar = (*drvrGlobalsHdl)->fileLocation.name[0] +1;
  410.     BlockMove(&numStr[1], &(*drvrGlobalsHdl)->fileLocation.name[nextChar], numLen);
  411.     (*drvrGlobalsHdl)->fileLocation.name[0] += numLen;
  412.  
  413.  
  414.     // Create a new file for this page, recklessly replacing any
  415.     // existing file with that name.
  416.  
  417.     FSpDelete(&(*drvrGlobalsHdl)->fileLocation);
  418.     anErr = FSpCreate(&(*drvrGlobalsHdl)->fileLocation, kFileCreator, kFileType, smSystemScript); 
  419.  
  420.  
  421.     // Open the new file, and write the beginning of the PICT file.
  422.  
  423.     if (!anErr)
  424.         anErr = FSpOpenDF(&(*drvrGlobalsHdl)->fileLocation, fsCurPerm, &(*drvrGlobalsHdl)->curFileRefNum);
  425.  
  426.     if (!anErr)
  427.         anErr = WriteStartOfPICTFile();
  428.  
  429.  
  430.     // Initialize this page's PICT's pixmap's bounds to (0,0,0,0).
  431.  
  432.     (*drvrGlobalsHdl)->pixMapBounds.top = 0;
  433.     (*drvrGlobalsHdl)->pixMapBounds.left = 0;
  434.     (*drvrGlobalsHdl)->pixMapBounds.bottom = 0;
  435.     (*drvrGlobalsHdl)->pixMapBounds.right = 0;
  436.  
  437.  
  438.     // Strip the page number we just added from the file name in our globals.
  439.     // This way, we won't have it when it comes time to set up the file name
  440.     // for the next page.
  441.  
  442.     (*drvrGlobalsHdl)->fileLocation.name[0] -= numLen;
  443.     HUnlock((Handle) drvrGlobalsHdl);
  444.  
  445.  
  446.     // Finally, forward gxStartSendPage so that GX and any overrides can do
  447.     // whatever they need to do.
  448.  
  449.     if (!anErr)
  450.         anErr = Forward_GXStartSendPage(pageFormat);
  451.  
  452.     return anErr;
  453. }
  454.  
  455.  
  456. /*    -----------------------------------------------------------------------
  457.  
  458.     SD_FinishSendPage is an override for gxFinishSendPage.  Here, we
  459.     forward the gxFinishPage message and write out the end of the PICT
  460.     file we created in SD_StartSendPage.
  461.  
  462.     -----------------------------------------------------------------------    */
  463.  
  464. OSErr SD_FinishSendPage()
  465. {
  466.     OSErr    anErr1, anErr2;
  467.     
  468.     // Forward the gxFinishPage message and write out the
  469.     // remainder of this page's PICT file.
  470.  
  471.     anErr1 = Forward_GXFinishSendPage();
  472.     anErr2 = WriteEndOfPICTFile();
  473.  
  474.     return (anErr1)? anErr1: anErr2;
  475. }
  476.  
  477.  
  478. /*    -----------------------------------------------------------------------
  479.  
  480.     SD_SetupImageData is an override for gxSetupImageData.  Here, we
  481.     forward the gxSetupImageData message and store the resolution for
  482.     the PICTs we'll create.
  483.  
  484.     -----------------------------------------------------------------------    */
  485.  
  486. OSErr SD_SetupImageData(gxRasterImageDataHdl hImageData)
  487. {
  488.     OSErr                anErr;
  489.     DriverGlobalsHdl    drvrGlobalsHdl = GetDriverGlobals();
  490.  
  491.     // Do the default setup.
  492.  
  493.     anErr = Forward_GXSetupImageData(hImageData);
  494.      
  495.     // Set up our PICT resolution based on the information in the
  496.     // gxRasterImageDataHdl that we're passed.
  497.  
  498.     (*drvrGlobalsHdl)->hRes = (*hImageData)->hImageRes;
  499.     (*drvrGlobalsHdl)->vRes = (*hImageData)->vImageRes;
  500.  
  501.     return (anErr);
  502. }
  503.  
  504.  
  505. /*    -----------------------------------------------------------------------
  506.  
  507.     CreateBuffers is the routine which creates and initializes our custom
  508.     buffers.
  509.  
  510.     -----------------------------------------------------------------------    */
  511.  
  512. OSErr CreateBuffers()
  513. {
  514.     OSErr            anErr;
  515.     BufferGroupHdl    theBuffs;
  516.     long            thisBig;
  517.     
  518.     thisBig = sizeof(BufferGroup) +
  519.               (sizeof(BufferEntry) * (kNumBuffs -1));
  520.     
  521.     // Create one handle for our buffer "group" and then individual handles for
  522.     // each buffer in the group.
  523.  
  524.     theBuffs = (BufferGroupHdl) TempNewHandle(thisBig, &anErr);
  525.  
  526.     if (!anErr)
  527.     {
  528.         short    idx;
  529.         Size    ourBufferSize, growDummy;
  530.  
  531.         // Initialize the buffer structure and store the buffer group in
  532.         // our instance context so we can get it later.
  533.         
  534.         (*theBuffs)->numBuffers = kNumBuffs;
  535.         (*theBuffs)->curBuff = 0;
  536.  
  537.         // We'll make kNumBuffs buffers that use a total of kMaxRAMToUse
  538.         // or kBuffRAMPercentage of the largest available block, whichever
  539.         // is less.
  540.     
  541.         ourBufferSize = (TempMaxMem(&growDummy) * kBuffRAMPercentage) / 100;
  542.         ourBufferSize = (ourBufferSize < kMaxRAMToUse)? ourBufferSize: kMaxRAMToUse;
  543.         ourBufferSize /= kNumBuffs;
  544.  
  545.         // Store the buffer size.  We subtract the size of a gxPrintingBuffer, since
  546.         // the bytes occupied by the gxPrintingBuffer structure are not actually
  547.         // available for storing data.  (Look at the structure if this sounds
  548.         // confusing.)
  549.  
  550.         (*theBuffs)->bufferSize = ourBufferSize - sizeof(gxPrintingBuffer);
  551.         
  552.         for (idx = (*theBuffs)->numBuffers; idx > 0; idx--)
  553.         {
  554.             OSErr    tempErr = anErr;
  555.  
  556.             (*theBuffs)->buff[idx -1].bufferIsDirty = false;
  557.             (*theBuffs)->buff[idx -1].curOffset = 0;
  558.             (*theBuffs)->buff[idx -1].printBuffer
  559.                     = (gxPrintingBuffer **) TempNewHandle(ourBufferSize, &tempErr);
  560.             
  561.             if (!anErr) anErr = tempErr;    // Don't worry about errors until we leave.
  562.                                             // The caller will send GXCleanupOpenConnection
  563.                                             // if we fail, and that will call DisposeBuffers.
  564.         }
  565.  
  566.         for (idx = (*theBuffs)->numBuffers; idx > 0; idx--)
  567.         {
  568.             if ((*theBuffs)->buff[idx -1].printBuffer != nil)
  569.                 HLock((Handle) (*theBuffs)->buff[idx -1].printBuffer);
  570.         }
  571.  
  572.         SetMessageHandlerInstanceContext(theBuffs);
  573.     }
  574.  
  575.     return anErr;
  576. }
  577.  
  578.  
  579. /*    -----------------------------------------------------------------------
  580.  
  581.     DisposeBuffers is the routine which disposes of our custom buffers.
  582.  
  583.     -----------------------------------------------------------------------    */
  584.  
  585. OSErr DisposeBuffers()
  586. {
  587.     BufferGroupHdl    bufferGroup = GetMessageHandlerInstanceContext();
  588.  
  589.     // Have we set up them there buffers?  Then erradicate 'em.
  590.  
  591.     if (bufferGroup != nil)
  592.     {
  593.         short    idx;
  594.         
  595.         // Dispose of any allocated buffers.
  596.  
  597.         for (idx = (*bufferGroup)->numBuffers; idx > 0; idx--)
  598.         {
  599.             if ((*bufferGroup)->buff[idx -1].printBuffer != nil)
  600.                 DisposeHandle((Handle) (*bufferGroup)->buff[idx -1].printBuffer);
  601.         }
  602.  
  603.         DisposeHandle((Handle) bufferGroup);
  604.         
  605.         // Indicate that we have no buffers.
  606.  
  607.         SetMessageHandlerInstanceContext(nil);
  608.     }
  609.  
  610.     return noErr;
  611. }
  612.  
  613.  
  614. /*    -----------------------------------------------------------------------
  615.  
  616.     FlushBuffers is the routine which flushes our custom buffers.  To do
  617.     this, it cycles through each one to see if there's data in it.  If so,
  618.     it sends gxDumpBuffer for the buffer, followed by gxFreeBuffer.
  619.  
  620.     -----------------------------------------------------------------------    */
  621.  
  622. OSErr FlushBuffers(BufferGroupHdl buffGrpHdl)
  623. {
  624.     OSErr    anErr = noErr;
  625.     short    idx;
  626.     char    hdlState;
  627.  
  628.     // Lock the buffer group.
  629.  
  630.     hdlState = HGetState((Handle) buffGrpHdl);
  631.     HLockHi((Handle) buffGrpHdl);
  632.  
  633.     // Send gxDumpBuffer and gxFreeBuffer for each buffer with data in it.
  634.  
  635.     for (idx = 0; idx < (*buffGrpHdl)->numBuffers; idx++)
  636.     {
  637.         if ((*buffGrpHdl)->buff[idx].bufferIsDirty)
  638.         {
  639.             // gxDumpBuffer will look at printbuffer.size to see how much
  640.             // data to write out.  Set it to the current offset, which just
  641.             // happens to equal the number of bytes we've stored in the buffer.
  642.  
  643.             (*(*buffGrpHdl)->buff[idx].printBuffer)->size =
  644.                 (*buffGrpHdl)->buff[idx].curOffset;
  645.  
  646.  
  647.             // Send gxDumpBuffer and gxFreeBuffer for this buffer.
  648.  
  649.             anErr = Send_GXDumpBuffer(*(*buffGrpHdl)->buff[idx].printBuffer);
  650.  
  651.             if (!anErr)
  652.                 anErr = Send_GXFreeBuffer(*(*buffGrpHdl)->buff[idx].printBuffer);
  653.  
  654.  
  655.             // Clear the buffer's dirty flag and reset its data offset.
  656.  
  657.             (*buffGrpHdl)->buff[idx].bufferIsDirty = false;
  658.             (*buffGrpHdl)->buff[idx].curOffset = 0;
  659.         }
  660.     }
  661.     
  662.     (*buffGrpHdl)->curBuff = 0;
  663.  
  664.     // Restore the state of the buffer group handle.
  665.     HSetState((Handle) buffGrpHdl, hdlState);
  666.     
  667.     return anErr;
  668. };
  669.  
  670.  
  671. /*    -----------------------------------------------------------------------
  672.  
  673.     WriteStartOfPICTFile is a routine that writes out the start of an
  674.     extended version 2 PICT that only contains a clip and a pixmap.  In
  675.     this routine we write out all the data up to the pixmap data.  However,
  676.     since we won't know things like the bounds and rowbytes until later,
  677.     we simply write out zeroes now, and update everything when we're done
  678.     imaging this page.  We do the updating in the routine
  679.     WriteEndOfPICTFile.
  680.  
  681.     -----------------------------------------------------------------------    */
  682.  
  683. OSErr WriteStartOfPICTFile()
  684. {
  685.     OSErr    anErr;
  686.     Ptr        dataPtr;
  687.  
  688.     // We need to write out the 512 unused bytes that every PICT file
  689.     // contains, plus 122 bytes that comprise the header and information
  690.     // that precedes the pixel data in our pixmap.  Since we do this at
  691.     // the start of the page, when SD_DumpBuffer and SD_WriteData write
  692.     // data to the file, they'll actually be filling out the pixel data
  693.     // in our PICT's pixmap.
  694.     //
  695.     // Anyway, create a clear pointer that's big enough to hold all the
  696.     // data that precedes our pixmap's pixels.  If there are no errors,
  697.     // write it out via our gxBufferData override.  When done, dispose
  698.     // of the pointer we used.
  699.  
  700.     dataPtr = NewPtrClear(512 +122);
  701.  
  702.     if (!(anErr = MemError()))
  703.     {
  704.         anErr = Send_GXBufferData(dataPtr, 512 +122, gxNoBufferOptions);
  705.         DisposePtr(dataPtr);
  706.     }
  707.  
  708.     return anErr;
  709. }
  710.  
  711.  
  712. /*    -----------------------------------------------------------------------
  713.  
  714.     WriteEndOfPICTFile is a routine that writes out the end of an
  715.     extended version 2 PICT that only contains a clip and a pixmap.  It
  716.     also updates the beginning of the PICT, with information about the
  717.     pixmap's bounds and so forth.  The beginning of the PICT was written
  718.     out with the WriteStartOfPICTFile routine.
  719.     
  720.     Writing out the end of the PICT simply involves writing out the end-
  721.     of-PICT opCode 0x00FF.  Most of the work done in this routine has to
  722.     do with updating the start-of-PICT data that we already wrote out.
  723.     
  724.     -----------------------------------------------------------------------    */
  725.  
  726. OSErr WriteEndOfPICTFile()
  727. {
  728.     OSErr                anErr;
  729.     fixed                hRes, vRes, hResScale, vResScale;
  730.     short                finalPictData;
  731.     short                initialPictData[61], curFileRefNum;
  732.     long                index = 0, pictSize;
  733.     Rect                drawRect, a72dpiDrawRect;
  734.     DriverGlobalsHdl    drvrGlobalsHdl = GetDriverGlobals();
  735.  
  736.     // Get the horizontal and vertical resolutions that we imaged
  737.     // at, along with the scaling necessary to apply to 72 dpi
  738.     // viewing rectangles for this image.
  739.  
  740.     hRes = (*drvrGlobalsHdl)->hRes;
  741.     vRes = (*drvrGlobalsHdl)->vRes;
  742.     hResScale = FixRatio(72, hRes >>16);  // FixRatio(hRes >>16, 72);
  743.     vResScale = FixRatio(72, vRes >>16);  // FixRatio(vRes >>16, 72);
  744.  
  745.     // Get the pixmap's native bounds, and calculate the correct
  746.     // viewing rectangle for 72 dpi.  We pin the top/left corner
  747.     // of each rectangle to 0,0 for convenience.
  748.  
  749.     drawRect = (*drvrGlobalsHdl)->pixMapBounds;
  750.     OffsetRect(&drawRect, -drawRect.left, -drawRect.top);
  751.     a72dpiDrawRect.top = a72dpiDrawRect.left = 0;
  752.     a72dpiDrawRect.bottom = (FixMul(ff(drawRect.bottom), vResScale) >>16);
  753.     a72dpiDrawRect.right = (FixMul(ff(drawRect.right), hResScale) >>16);
  754.  
  755.     // Flush our buffers. (Yes, since we're doing our own buffer
  756.     // management, we could just call FlushBuffers, but this is how
  757.     // you'd do it otherwise.)
  758.  
  759.     anErr = Send_GXWriteData(nil, 0);
  760.     nrequire(anErr, FlushBuffersFailed);
  761.  
  762.     // Get the current file's refNum.  Since we flushed the buffers,
  763.     // we can go back and see how big the PICT is.  Do so.
  764.  
  765.     curFileRefNum = (*drvrGlobalsHdl)->curFileRefNum;
  766.     anErr = GetEOF(curFileRefNum, &pictSize);
  767.     nrequire(anErr, GetEOFFailed);
  768.  
  769.     // If necessary, add a $00 to word align the endPict opcode.
  770.     
  771.     if ((pictSize & 1) != 0)
  772.     {
  773.         finalPictData = 0;
  774.         anErr = Send_GXWriteData((Ptr) &finalPictData, 1);
  775.         nrequire(anErr, WordAlignFailed);
  776.         ++pictSize;
  777.     }
  778.  
  779.     // Write the endPict opcode.
  780.  
  781.     finalPictData = 0x00FF;
  782.     anErr = Send_GXWriteData((Ptr) &finalPictData, 2);
  783.     nrequire(anErr, SendFinalDataFailed);
  784.  
  785.     // Now, we're ready to update the information that precedes
  786.     // the pixmap data.  Set our file position to 512 bytes from
  787.     // the start.  That puts us just past the obsolete PICT header
  788.     // that we're required to include.
  789.  
  790.     anErr = SetFPos(curFileRefNum, fsFromStart, 512);
  791.     nrequire(anErr, SetFPosFailed);
  792.  
  793.     // Store the low word of picsize.
  794.  
  795.     initialPictData[index] = pictSize & 0xFFFF;
  796.     ++index;
  797.  
  798.     // Store the picFrame at 72 dpi.
  799.  
  800.     initialPictData[index] = a72dpiDrawRect.top;
  801.     ++index;
  802.     initialPictData[index] = a72dpiDrawRect.left;
  803.     ++index;
  804.     initialPictData[index] = a72dpiDrawRect.bottom;
  805.     ++index;
  806.     initialPictData[index] = a72dpiDrawRect.right;
  807.     ++index;
  808.  
  809.     // Store the pict version opcode ($0011).
  810.  
  811.     initialPictData[index] = 0x0011;
  812.     ++index;
  813.  
  814.     // Store the pict version ($02FF).
  815.  
  816.     initialPictData[index] = 0x02FF;
  817.     ++index;
  818.  
  819.     // Store the header opcode ($0C00).
  820.  
  821.     initialPictData[index] = 0x0C00;
  822.     ++index;
  823.  
  824.     // Store the header version (-2).
  825.  
  826.     initialPictData[index] = -2;
  827.     ++index;
  828.  
  829.     // Store the reserved word (0).
  830.  
  831.     initialPictData[index] = 0;
  832.     ++index;
  833.  
  834.     // Store the native horizontal resolution (fixed) of the source data.
  835.  
  836.     initialPictData[index] = hRes >>16;
  837.     ++index;
  838.     initialPictData[index] = hRes & 0xFFFF;
  839.     ++index;
  840.  
  841.     // Store the native vertical resolution (fixed) of the source data.
  842.  
  843.     initialPictData[index] = vRes >>16;
  844.     ++index;
  845.     initialPictData[index] = vRes & 0xFFFF;
  846.     ++index;
  847.  
  848.     // Store the native source rectangle.
  849.  
  850.     initialPictData[index] = drawRect.top;
  851.     ++index;
  852.     initialPictData[index] = drawRect.left;
  853.     ++index;
  854.     initialPictData[index] = drawRect.bottom;
  855.     ++index;
  856.     initialPictData[index] = drawRect.right;
  857.     ++index;
  858.  
  859.     // Store the reserved longword (0L).
  860.  
  861.     initialPictData[index] = 0;
  862.     ++index;
  863.     initialPictData[index] = 0;
  864.     ++index;
  865.  
  866.     // Store the clip opcode (1).
  867.  
  868.     initialPictData[index] = 1;
  869.     ++index;
  870.     
  871.     // Store the size of the clip region data (10).
  872.  
  873.     initialPictData[index] = 10;
  874.     ++index;
  875.  
  876.     // Store the clip rectangle.
  877.  
  878.     initialPictData[index] = drawRect.top;
  879.     ++index;
  880.     initialPictData[index] = drawRect.left;
  881.     ++index;
  882.     initialPictData[index] = drawRect.bottom;
  883.     ++index;
  884.     initialPictData[index] = drawRect.right;
  885.     ++index;
  886.  
  887.     // Store the opBitsRect opcode ($009A).
  888.  
  889.     initialPictData[index] = 0x009A;
  890.     ++index;
  891.  
  892.     // Store the pixmap's baseAddr placeholder (always $000000FF).
  893.  
  894.     initialPictData[index] = 0x0000;
  895.     ++index;
  896.     initialPictData[index] = 0x00FF;
  897.     ++index;
  898.  
  899.     // Store the rowBytes (high bit must be set for a pixmap).
  900.  
  901.     initialPictData[index] = (*drvrGlobalsHdl)->pixMapRowBytes | 0x8000;
  902.     ++index;
  903.  
  904.     // Store the pixmap bounds at source resolution.
  905.  
  906.     initialPictData[index] = drawRect.top;
  907.     ++index;
  908.     initialPictData[index] = drawRect.left;
  909.     ++index;
  910.     initialPictData[index] = drawRect.bottom;
  911.     ++index;
  912.     initialPictData[index] = drawRect.right;
  913.     ++index;
  914.  
  915.     // Store the pixmap version (0).
  916.  
  917.     initialPictData[index] = 0;
  918.     ++index;
  919.  
  920.     // Store the pixmap packing type (2 == we dropped pad bytes).
  921.  
  922.     initialPictData[index] = 2;
  923.     ++index;
  924.  
  925.     // Store the packing size (0L).
  926.  
  927.     initialPictData[index] = 0;
  928.     ++index;
  929.     initialPictData[index] = 0;
  930.     ++index;
  931.  
  932.     // Store the horizontal resolution (fixed) of the source data.
  933.  
  934.     initialPictData[index] = hRes >>16;
  935.     ++index;
  936.     initialPictData[index] = hRes & 0xFFFF;
  937.     ++index;
  938.  
  939.     // Store the vertical resolution (fixed) of the source data.
  940.  
  941.     initialPictData[index] = vRes >>16;
  942.     ++index;
  943.     initialPictData[index] = vRes & 0xFFFF;
  944.     ++index;
  945.  
  946.     // Store the pixelType (direct == 16).
  947.  
  948.     initialPictData[index] = 16;
  949.     ++index;
  950.  
  951.     // Store the pixelSize (32 (packed to 24) bits per pixel).
  952.  
  953.     initialPictData[index] = 32;
  954.     ++index;
  955.  
  956.     // Store the pixel component count (3).
  957.  
  958.     initialPictData[index] = 3;
  959.     ++index;
  960.  
  961.     // Store the pixel component size (8).
  962.  
  963.     initialPictData[index] = 8;
  964.     ++index;
  965.  
  966.     // Store the offset to next plane (0).
  967.  
  968.     initialPictData[index] = 0;
  969.     ++index;
  970.     initialPictData[index] = 0;
  971.     ++index;
  972.  
  973.     // Store the ctSeed (0L).
  974.  
  975.     initialPictData[index] = 0;
  976.     ++index;
  977.     initialPictData[index] = 0;
  978.     ++index;
  979.  
  980.     // Store the ctFlags (0).
  981.  
  982.     initialPictData[index] = 0;
  983.     ++index;
  984.  
  985.     // Store the ctSize (-1 == 0 entries.  Unused for direct pixmaps anyway).
  986.  
  987.     initialPictData[index] = -1;
  988.     ++index;
  989.  
  990.     // Store the source rectangle at source resolution.
  991.  
  992.     initialPictData[index] = drawRect.top;
  993.     ++index;
  994.     initialPictData[index] = drawRect.left;
  995.     ++index;
  996.     initialPictData[index] = drawRect.bottom;
  997.     ++index;
  998.     initialPictData[index] = drawRect.right;
  999.     ++index;
  1000.  
  1001.     // Store the destination rectangle at source resolution.
  1002.  
  1003.     initialPictData[index] = drawRect.top;
  1004.     ++index;
  1005.     initialPictData[index] = drawRect.left;
  1006.     ++index;
  1007.     initialPictData[index] = drawRect.bottom;
  1008.     ++index;
  1009.     initialPictData[index] = drawRect.right;
  1010.     ++index;
  1011.  
  1012.     // Store the transfer mode (ditherCopy).
  1013.  
  1014.     initialPictData[index] = ditherCopy;
  1015.     ++index;
  1016.  
  1017.     // The number of bytes we've got to write is index *2 (since
  1018.     // we bumped index at every word we stored).  Empirically, this
  1019.     // comes out to 122 bytes, which explains the 122 bytes in
  1020.     // WriteStartOfPICTFile and the 61 words allocated for
  1021.     // initialPictData.  If you change the data that's written into
  1022.     // this file, make sure you update those two values!!
  1023.     //
  1024.     // Write out the updated data.
  1025.  
  1026.     index *= 2;
  1027.     anErr = FSWrite(curFileRefNum, &index, initialPictData); 
  1028.  
  1029. SetFPosFailed:
  1030. SendFinalDataFailed:
  1031. WordAlignFailed:
  1032. GetEOFFailed:
  1033. FlushBuffersFailed:
  1034.  
  1035.     return anErr;
  1036. }
  1037.  
  1038.  
  1039.